TITL DAI FIRMWARE D3F4-D61F V1.1 ORG :D3F4 * * * ******************** * READ FILE HEADER * ******************** * * Locates a file on tape and reads leader. * Exit: Interrupts are disabled. BCDEHL preserved. * RHDR CALL :D98F Disable sound interrupt CALL :D480 Find sync pattern CALL :D4D4 Read flag type byte JC :D3F4 Again if reading error CPI :55 JNZ :D3F4 Again if not flag byte CALL :D4D4 Read file type byte JC :D3F4 Again if reading error RET * ********************* * WRITE FILE LEADER * ********************* * * Writes a leader for program or data block on tape. * Disables interrupts which could cause problems. * * Entry: at WHDR: Entry if not during run program. * at WHD20: If during run of program. * Exit: BCDEHL preserved. * WHDR CALL :DAFF Print 'SET RECORD, START DBL :DB9C TAPE, TYPE SPACE' CALL :D7CB Wait for spacebar pressed WHD20 CALL :D42E Switch on cassette motors DI Disable interrupts NOP NOP CALL :D4ED Write leader MVI A,:55 Get flag byte JMP :D509 Write flag byte * ************** * (Not used) * ************** * MPT27 CALL :D2F1 Write block on tape NOP NOP * ********************** * WRITE FILE TRAILER * ********************** * * Write a trailer for program or datablock. * * Entry: Length of trailer in C. * Exit: A=0, BCDEHL preserved. * *WTRL CWCLOS CALL :D550 Write trailer bytes EI Enable interrupts JMP :D445 Stop cassette motors * ************************* * START CASSETTE MOTORS * ************************* * * Turns on motor of selected cassettedeck and * waits 665 msec. * * Exit: All registers preserved. * CASST PUSH PSW LDA :0040 Load POROM ORI :30 Disable cassette motors PUSH H LXI H,:013D Addr CASSL XRA M Get selected cassette POP H STA :0040 Remember POROM STA :FD06 Switch cassette motor on CALL :DE41 Delay POP PSW RET * ************************ * STOP CASSETTE MOTORS * ************************ * * Switches off cassettemotors. * * Exit: All registers preserved. * *CRCLOS CASSP PUSH PSW LDA :0040 Load POROM ORI :30 Disable cassette motors STA :0040 Remember POROM STA :FD06 Switch cassette motors off POP PSW RET * ************ * READ BIT * ************ * * Reads one bit from tape. * * Entry: Address input port in HL. Input low state. * Exit: CY=0: sign bit of A is bit read. * CY=1: reading error. * BHL preserved. * RBIT XRA A MOV D,A MOV B,A MOV C,A REM * 1st impulse: REM RBT10 DCR B JZ :D47E Too long low ORA M JP :D457 Wait for high RBT30 DCR C JZ :D47E Too long high DCR D ANA M JM :D45F Wait low LXI B,:0000 REM * 2nd impulse: REM RBT40 DCR B JZ :D47E Too long low ORA M JP :D46B Wait high again RBT50 DCR C JZ :D47E Too long high INR D ANA M JM :D473 Wait low MOV A,D RET REM * If error: REM RBT90 STC Set CY if error RET * *************** * READ LEADER * *************** * * Finds a section of leader on the tape. * * Entry: No conditions. * Exit: BCDEHL preserved, interrupts disabled. * RLEAD PUSH B PUSH D PUSH H MVI B,:28 Estimate of impulse length LXI H,:FD00 Address input port RDL05 MVI A,:FF RDL10 EI Enable interrupts NOP (here cursor flashes) DI Disable interrupts ANA M JM :D48A Wait low MOV C,B Estimated length in C MVI D,:14 Needs this many cycles for REM synchronisation. Must be REM more than trailer length. RDL30 MVI E,:00 XRA A RDL40 DCR E JZ :D488 Too long low; start again ORA M JP :D497 Wait high MVI B,:00 RDL50 INR B JZ :D488 Too long high; start again ANA M JM :D4A1 Wait low MOV A,B SUB C Compare impulse length REM with estimate JP :D4B0 CMA ) INR A ) 2-complement if <0 RDL60 MOV E,A Store difference in E MOV A,C Calculate margin ANI :F0 RAR RAR RAR Margin: 1/8th of estimate CMP E Compare with difference JC :D4C3 Not within margin REM * If sync archieved: REM DCR D JNZ :D494 Next impulse until D=0 INR D JMP :D494 Next impulse until out REM of margin REM * If out of margin: REM RDL70 DCR D JNZ :D488 Not synchronised; again XRA A RDL80 ORA M JP :D4C8 Wait high RDL90 ANA M JM :D4CC Wait low POP H POP D POP B RET * ************* * READ BYTE * ************* * * Reads one byte from tape. * * Entry: No conditions. * Exit: CY=0: Byte read in A. * CY=1: Some error. * BCDEHL preserved. * RBYTE PUSH B PUSH D PUSH H LXI H,:FD00 Address input port MVI E,:FE RBY10 CALL :D453 Read bit JC :D4E9 If reading error; CY=1 RAL MOV A,E RAL MOV E,A Shift bit into E JC :D4DC Next bit RBY20 POP H 8 bits read, no error POP D POP B RET * **************** * WRITE LEADER * **************** * * Writes a leader on the tape. From WLD10 also used * to write a trailer. * * Entry: No conditions. * Exit: A=0, BCDEHL preserved. * WLEAD NOP PUSH B PUSH H LHLD :02E6 Get leader impulse length LXI B,:07E8 Period for synchr. WLD10 CALL :D524 Write bit DCX B MOV A,B ORA C JNZ :D4F6 Write many bits LHLD :02E8 Get impulse length data bit CALL :D524 Write a data '1' bit to end POP H POP B NOP RET * ************** * WRITE BYTE * ************** * * Write a byte to tape. * * Entry: Byte to be written in A. * Exit: All registers preserved. * WBYTE PUSH PSW PUSH B PUSH D PUSH H LHLD :02E8 Get impulse length bit '1' MOV E,H MOV D,L DE: inpulse length bit '0' MVI B,:08 8 bits to write WBY10 RAL Set/reset CY for kind of bit CC :D524 Write data '1' bit XCHG CNC :D524 Write data '0' bit XCHG DCR B JNZ :D514 Next bit JMP :CB56 Pop all, ret * ************* * WRITE BIT * ************* * * Write 2 impulses on tape, one long, one short. * * Entry: H: Half count first cycle. * L: Half count second cycle. * Exit: All registers preserved. * WBIT PUSH PSW PUSH D PUSH H MOV L,H LXI D,:FD06 Address output port CALL :D53C Write 1st impulse POP H PUSH H MOV H,L MOV A,L SUI :08 Allow for return to WBYTE MOV L,A CALL :D53C Write 2nd impulse POP H POP D POP PSW RET * *************** * WRITE CYCLE * *************** * * Writes one impulse (hi/lo) on tape. Two cycles * are required for one bit. * * Entry: DE: Address output port. * HL: Impulse length constants. * Exit: HL = 0. BCDE preserved. * WCYC LDA :0040 POROM in A ORI :01 lsb = 1 STAX D Output port is made '1' WCY10 DCR H JNZ :D542 Write '1' until H=0 DCR L DCR L DCR L Allow for return to WBIT DCR A STAX D Output port is made '0' WCY20 DCR L JNZ :D54B Write '0' until L=0 RET * ********************** * WRITE TRAILER BITS * ********************** * * Writes trailer bits after a block on tape. * * Entry: Number of trailer bits in C. * Exit: A=0, other registers preserved. * F corrupted. * WTRLX PUSH B PUSH H LHLD :02EA Trailer impulse length MVI B,:00 JMP :D4F6 Write trailer bits STA :0131 ] Output to screen JMP :DD49 ] Ignore line if break REM pressed * ******************************** * INITIALISE KEYBOARD POINTERS * ******************************** * * Set all keyboard pointers to default values. * * Entry: Address ASCII-table in HL (3E8C5). * Exit: BCDE preserved. * *KLIRS KBINIT SHLD :02A7 Load pointer ASCII-table KLIRP XRA A STA :02B9 Allow complete scan routine STA :02C3 CTRL not pressed LXI H,:02BA SHLD :02BE Set KLIIN ) Ignore SHLD :02C0 Set KLIOU ) previous inputs CMA STA :02C4 BREAK pointer = FF RET * ************************************** * KEYBOARD INTERRUPT SERVICE (RST 6) * ************************************** * * Current interrupt mask is saved. Only stack and * clock interrupts are allowed. Keyboard timer 4 * is re-loaded. * KBXCT is counted down: abort if not 0. * Else: scan keyboard and store result. * * Entry: None. * Exit: All registers + int. mask preserved. * KBINT PUSH PSW PUSH B PUSH D LDA :005F PUSH PSW Preserve current int. mask MVI A,:84 ) STA :FFF8 ) Allow stack and clock STA :005F ) interrupts only EI CALL :D99D Reload keyboard timer LXI H,:01C1 DCR M Decr. keyb.scan time count JNZ :D9CD No scanning if <>0 REM * if KBXCT = 0: REM MVI M,:02 Set keyb. scan time counter CALL :D59A Scan keyboard, store result JMP :D9CD Restore int.mask; ret. * ******************************* * SCAN KEYBOARD, STORE RESULT * ******************************* * * Exit: All registers corrupted. * KBSCAN LXI D,:FFF1 Input port from keyboard LXI H,:FFF7 Output port to keyboard LXI B,:02C4 BREAK pointer DI MVI M,:40 Scan row 6 LDAX D and get result EI ADD A Check for BREAK pressed JM :D606 If BREAK pressed CALL :D750 Update BREAK pointer LDA :02B9 Get BREAK pointer ORA A Scan for BREAK only? JNZ :D605 Then abort REM * Scan all rows and store result in MAP1: REM LXI B,:02A9 MAP1 for currently REM pressed key PUSH B Preserve MAP1 addr INR A Determine row KEB10 PUSH PSW DI MOV M,A Scan row LDAX D Get result EI STAX B Store result in MAP1 INX B POP PSW ADD A Determine next row JNC :D5BB Scan next row if not ready REM * REPT handling: REM LDA :02AF ANI :20 Check if REPT pressed MOV B,A Store result LXI H,:02C2 Addr. REPT counter MOV A,M Get contents MVI M,:01 Update it for immediate scan JZ :D5DF If REPT not pressed DCR A Else MOV M,A Decr. REPT counter JNZ :D604 If <>0, abort scan MVI M,:02 Else RPCNT=2 MVI B,:FF Set B=FF for REPT pressed REM * ASCII-value of key pressed into KLIND: REM KEB40 POP H Get addr MAP1 PUSH H Save addr. MAP1 LXI D,:02B1 Get addr. MAP2 MVI C,:00 KEB50 MOV A,M Get result scan current REM row in A DCR B INR B REPT pressed ? JNZ :D5F0 If REPT pressed XCHG XRA M ) Check if new input XCHG ) ANA M ) KEB60 ORA A ) CNZ :D632 If new: Get ASCII-code REM and store it in KLIND INX D INX H Next row INR C MOV A,C CPI :08 All rows checked? JNZ :D5E6 Next row if not KEB70 POP D Get MAP1 addr in DE PUSH D MOV B,H ) Get MAP2 addr in HL MOV C,L ) CALL :DE4F Transfer (MAP1) into MAP2 KEB80 POP D Scrap KEB81 RET REM * if BREAK pressed: REM KEB90 PUSH B Save Breakpntr CALL :D8A6 All sound off POP B NOP CALL :D445 Stop cassette motors LDAX B Get KBRFL INR A JZ :D605 If KBRFL=FF: break acknow- REM ledged already STAX B Else: store new KBRFL CPI :20 JNZ :D605 If new KBRFL<>20: wait for REM soft-break to be accepted CALL :D563 Else: init keyb. pointers JMP :C80C Print 'BREAK', return to REM monitor * * UNL KLIRS EQU KBINIT CRCLOS EQU CASSP WTRL EQU CWCLOS LST END